package publish

import (
	"errors"
	"fmt"
	"manager/config"
	"time"

	MQTT "github.com/eclipse/paho.mqtt.golang"
	"hiscene.com/openplatform/common/logger"
)

////////////////////////////////////////////////////////////////////////////////

var (
	client   MQTT.Client
	stop     chan bool
	sendchan chan *sendData
	outtime  = time.Second * 2 // 发送超时
)

// 错误定义
var (
	ErrToken = errors.New("token create error")
)

////////////////////////////////////////////////////////////////////////////////

type sendData struct {
	mac   string
	key   string
	value string
}

////////////////////////////////////////////////////////////////////////////////

// Start 启动
func Start(opts *MQTT.ClientOptions) error {
	opts.SetOnConnectHandler(onConnect)
	opts.SetConnectionLostHandler(lostConnect)
	if len(config.MQTTCfg.ID) > 0 {
		opts.SetClientID(fmt.Sprintf("%v_publish", config.MQTTCfg.ID))
	}

	client = MQTT.NewClient(opts)
	token := client.Connect()
	if token == nil || token.Wait() == false {
		logger.Log4g.Error("publish start connect token fail")
		return ErrToken
	}

	err := token.Error()
	if err != nil {
		logger.Log4g.Error("publish start connect token error: %v", err)
		return err
	}

	sendchan = make(chan *sendData, 10)
	stop = make(chan bool)

	go func() {
		for {
			select {
			case <-stop:
				{
					goto EXIT
				}
			case sd, ok := <-sendchan:
				{
					if ok == false || sd == nil {
						continue
					}

					if client.IsConnected() == false {
						if tkn := client.Connect(); tkn.Wait() && tkn.Error() != nil {
							logger.Log4g.Error("publish go run connect token error: %v", tkn.Error())
							continue
						}
					}

					tkn := client.Publish(fmt.Sprintf("%s/%s", config.MQTTCfg.STOCTopic, sd.mac), 2, false,
						fmt.Sprintf("[%s]%s", sd.key, sd.value))

					go func() {
						tsd := sd
						if tkn.WaitTimeout(outtime) == false {
							logger.Log4g.Error("publish go run publish token timeout failed, mac: %v, key: %v, value: %v", tsd.mac, tsd.key, tsd.value)
						} else {
							err = tkn.Error()
							if err != nil {
								logger.Log4g.Error("publish go run publish token error: %v, mac: %v, key: %v, value: %v", err, tsd.mac, tsd.key, tsd.value)
							}
						}
					}()
				}
			}
		}
	EXIT:
		client.Disconnect(250)
		client = nil
		close(sendchan)
		sendchan = nil
		stop <- true
	}()
	return nil
}

// Stop 关闭
func Stop() {
	opts := client.OptionsReader()
	logger.Log4g.Trace("mqtt publish client id: %v stop service", opts.ClientID())

	stop <- true
	<-stop
	close(stop)
}

// Send 发送数据
func Send(mac, key, value string) {
	if sendchan != nil {
		sendchan <- &sendData{
			mac:   mac,
			key:   key,
			value: value,
		}
	}
}

////////////////////////////////////////////////////////////////////////////////

func onConnect(clt MQTT.Client) {
	opts := clt.OptionsReader()
	logger.Log4g.Trace("publish mqtt connected, client id: %v, address: %v", opts.ClientID(), opts.Servers())
}

func lostConnect(clt MQTT.Client, err error) {
	opts := clt.OptionsReader()
	logger.Log4g.Trace("publish mqtt lost connect, client id: %v, address: %v, error: %v", opts.ClientID(), opts.Servers(), err)
}
